<?php

class App_Source_Users_Mapper extends Mozg_Mapper_Data
{

	private $_source;

	protected $_entityPath = 'entity/user';
	protected $_filterPath = 'filter/user';

	public function __construct()
	{
		$this->_source = Mozg_Source::get('default');
	}

	private function User()
	{
    	return Mozg::User();
	}

	public function GetSuperUser()
	{
		return Mozg_Cfg::Get('global/superuser');
	}

	protected function FindSuperUser($filter = null)
	{
		$user = $this->GetSuperUser();
		if (!($filter instanceof Mozg_Property_Params)) $filter = $this->GetFilter($filter);

		if (sizeof($filter->GetGroups())) return false;

		if ($filter->HasSet('id') && ($filter->GetId() != $user->GetId())) return false;

		if ($filter->HasSet('userName'))
		{
			if ($filter->GetSearchPartUserName())
			{
				if (strpos($user->GetUserName(), $filter->GetUserName()) !== 0)
				{
					return false;
				}
			}
			else if ($filter->GetUserName() != $user->GetUserName())
			{
				return false;
			}
		}

		return $user;
	}

	private function GetSqlFromFilter($filter = null)
	{
		$sqlFilter = array('where' => array(), 'join' => array());
		if (!($filter instanceof Mozg_Property_Params)) $filter = $this->GetFilter($filter);

		if ($filter->HasSet('id'))
		{
			$sqlFilter['where'][] = 'u.user_id = ' .(int)$filter->GetId();
		}

		if (sizeof($filter->GetGroups()))
		{
			$sqlFilter['where'][] = 'g.id is NULL OR g.id in (' . implode(',', $filter->GetGroups()) . ') ';
		}

		if ($filter->HasSet('userName'))
		{
			$sqlName = str_replace('%', '\%', $filter->GetUserName());

			if ($filter->GetSearchPartUserName())
			{
				$sqlName = $sqlName. "%";
			}

			$sqlFilter['where'][] = 'u.username LIKE ' .$this->_source->quote($sqlName);
		}

		$sqlFilter['where'] = sizeof($sqlFilter['where']) ? '(' .implode(') and (', $sqlFilter['where']). ')' : '';
		$sqlFilter['join'] = sizeof($sqlFilter['join']) ?  implode(' ', $sqlFilter['join']) : '';

		return $sqlFilter;
	}

	private $_superUserFound = false;
	private $_totalRows = 0;

	public function GetTotalRows()
	{
		if (!is_int($this->_totalRows))
		{
			$this->_totalRows = $this->_source->query("SELECT FOUND_ROWS()")->fetchColumn();
			if ($this->_superUserFound)
			{
				$this->_totalRows++;
			}
		}

		return $this->_totalRows;
	}

	protected function Find($filter = null, Mozg_Paginator $paginator = null, $fields = array())
	{
		$sqlFilter = $this->GetSqlFromFilter($filter);

		$this->_totalRows = null;

        $rows = $this->_source->fetchObjectAll("SELECT " .($paginator ? "SQL_CALC_FOUND_ROWS" : "" ). "
												   " .$this->_source->Table('users')->GetSqlMap($fields, "u"). ",
								                   " .$this->_source->Table('groups')->GetSqlMap(array(), "g", "group"). "
							                 FROM %%users%% u
							                 		left join %%user_groups%% g on(u.user_group=g.id)
							                 " .($sqlFilter['where'] ? " WHERE ". $sqlFilter['where'] : ""). "
							                 ORDER by u.user_group, u.user_id
							                 " .( $paginator ? "LIMIT " . $paginator->GetSqlLimit() : '' ). "
							               ", $this->_entityPath);

        $superUser = $this->FindSuperUser($filter);
        if ($superUser)
        {
        	$this->_superUserFound = true;
        	$rows[] = $superUser;
        }
        else
        {
        	$this->_superUserFound = false;
        }

        return $rows;
	}

	public function GetList($filter = null, Mozg_Paginator $paginator = null)
	{
		return $this->Find($filter, $paginator);
	}

	public function GetOne($filter = null)
	{
		return current($this->Find($filter, new Mozg_Paginator(1,1)));
	}

	public function Save(Mozg_Property_Params $obj)
	{
		if (!$obj->Validator()->Validate()) return false;

		$this->Prepare($obj);

		if ($obj->GetId())
		{
			$filter = $this->GetFilter();
			$filter->SetId($obj->GetId());
			return $this->Update($obj, $filter);
		}

		return $this->Insert($obj);
	}

	private function Insert(Mozg_Property_Params $obj)
	{
		$fields = $this->_source->Table('users')->GetSqlInsert($obj);
		$num = $this->_source->exec("INSERT INTO %%users%%(" .$fields['fields']. ") VALUES (" .$fields['values']. ")");

		if ($num)
		{
			$obj->SetId($this->_source->lastInsertID());
			return true;
		}

		return false;
	}

	private function Update(Mozg_Property_Params $obj, $filter = null)
	{
		if ($this->User()->IsSuperUser() && ($obj->GetId() == $this->User()->GetId()))
		{
			$superUser = $this->GetSuperUser();
			$superUser->ImportData($obj->ExportData());
			$num = (bool)Mozg_Cfg::Save('global/superuser');
		}
		else
		{
			$sqlFilter = $this->GetSqlFromFilter($filter);

			$updateStr = $this->_source->Table('users')->GetSqlUpdate($obj);
			if (strlen($updateStr))
			{
				$num = (bool)$this->_source->exec("update %%users%% u
									                 		left join %%user_groups%% g on(u.user_group=g.id)
												      set
												       	 " .$updateStr. "
												      " .($sqlFilter['where'] ? " WHERE ". $sqlFilter['where'] : ""). "
											     ");
			}
			else
			{
				$num = true;
			}
		}

		if ($num)
		{
			return true;
		}

		return false;
	}

	private function Prepare(Mozg_Property_Params $obj)
	{
    	$grantGroups = array_intersect($obj->GetGrantedGroups(), $this->User()->GetAvailableGroups());
        $obj->SetGrantedGroups($grantGroups);
	}

    public function Delete($filter = null)
    {
    	$sqlFilter = $this->GetSqlFromFilter($filter);

        $num = (bool)$this->_source->exec("DELETE
		        									u
		        								FROM %%users%% u
								                 		left join %%user_groups%% g on(u.user_group=g.id)
		        								" .($sqlFilter['where'] ? " WHERE ". $sqlFilter['where'] : ""). "
		        							");

    	if ($num)
    	{
    		return true;
    	}

    	return false;
    }
}